package com.xms.plugin.core;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * <p>
 * PluginServiceRegistrar
 * </p>
 *
 * @author migo
 * @since 2021/10/15
 */
@Component
public class PluginServiceRegistrar implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
    public void PluginServiceRegistrar() {

    }

    private ApplicationContext applicationContext; // 上下文，在这里用来取Bean

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {

        /*// 手动注册的Bean类型 ， 由于我要注册的其实是 接口的实现类
        // 所以采用FactoryBean方式创建Bean
        // 若仅仅需要对Bean注入值，可以直接指定想创建的Bean的class
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(TestFactory.class); //这里可以直接改成TestFactory.class
        AbstractBeanDefinition definition = builder.getRawBeanDefinition();

        //亦可通过setBeanClass方式指定创建的类
        //definition.setBeanClass(TestFactory.class);

        //由于TestBean同时有两个不同名的Bean实例，需要手动指定注入
        TestBean c = applicationContext.getBean("testBean", TestBean.class);
        definition.getPropertyValues().addPropertyValue("testBean",c); //set 方式autowired，需要指定属性有set方法

        // 构造方法autowired，FactoryBean 的 construct 方法必须有 ， 两种注入方式选其一
        // definition.getConstructorArgumentValues().addGenericArgumentValue();

        // 对 TestFactory 中的所有属性默认使用 byType 的依赖注入，若同一class有多个bean，则会报错。
        definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);

        beanDefinitionRegistry.registerBeanDefinition(TestService.class.getName(), definition);*/

    }

    public void registerBean(String file, String clazzName) throws Exception{
        URL url = new File(file).toURI().toURL();

//        URLClassLoader loader = (URLClassLoader) ApplicationBootstrap.class.getClassLoader();
//        Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
//        add.setAccessible(true);
//        add.invoke(loader, url);

        URLClassLoader loader = new URLClassLoader(new URL[]{url});
//        String clazzName = "test1.controller.MyTestController1";
        Class<?> clazz = loader.loadClass(clazzName);


//        applicationContext.getClassLoader().loadClass("test.MyController");
//        DefaultListableBeanFactory factory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();

        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();

        //设置当前bean定义对象是单利的
        beanDefinition.setScope("singleton");

        //将变量首字母置小写
        String beanName = StringUtils.uncapitalize(clazzName);

        beanName =  beanName.substring(beanName.lastIndexOf(".")+1);
        beanName = StringUtils.uncapitalize(beanName);

        //将applicationContext转换为ConfigurableApplicationContext
        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;

        // 获取bean工厂并转换为DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();


        defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("postProcessBeanFactory");
    }

    // 获得上下文
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
